03 / 10

What is a sensible payload schema design for a document search system that needs to support filtering by date range, category, and access permissions?

DateTime, keyword, and keyword-array types with matching indexes

The schema should use the payload type that matches the filter's access pattern, and each filterable field should have a payload index with a matching schema. For date range filtering, use the datetime payload type and a datetime index - this gives efficient range queries and lets the planner prune segments whose date ranges do not overlap. For category filtering, use a keyword field and a keyword index - keyword indexes are hash-based and support exact-match must and must_not filters. For access permissions, which are typically a list of roles or groups, use a keyword-array field and a keyword index; Qdrant's keyword index supports array values and can match if any element matches (should) or require all (must). The schema should also include a stable point ID scheme so that a document can be reconstructed from a payload lookup if needed, and a reference to the source document so that chunks or multiple embeddings of the same document can be traced back.

The mechanism behind each choice is the index structure. A datetime index stores timestamps in a sorted structure that supports range queries and min/max statistics, which is what enables both the range filter and the segment-level pruning. A keyword index maps each distinct value to a posting list of point IDs, so an exact-match filter resolves to a set lookup; for an array field, the same structure supports membership tests. A field that is filtered with a range but indexed as a keyword will not get range pruning and will be slower. A field that is filtered with exact match but not indexed will require a scan of the payload for every candidate. The schema must therefore reflect how the field is actually queried, not just what type the value happens to be. Access permissions are a good example: if they are stored as a list of roles and the query asks 'which documents can this user see', the filter is a should over the roles, which a keyword index on an array field handles efficiently. If the query asks 'which documents require all of these roles', the filter is a must over the roles, which the same index handles. If permissions are hierarchical or group-based, the application must expand the user's group memberships into a list before querying.

  1. 1

    Date range: datetime payload type, datetime index. Supports range queries and segment pruning.

  2. 2

    Category: keyword payload type, keyword index. Supports exact match and must/must_not filters.

  3. 3

    Access permissions: keyword-array payload type, keyword index. Supports any-of (should) and all-of (must) filters.

  4. 4

    Stable IDs: use deterministic point IDs (e.g. the document ID or a hash of content) so that upserts are idempotent and references are stable.

  5. 5

    Source reference: store a document_id field so chunks or multiple embeddings can be traced back to their source.

  6. 6

    Tenant discriminator: if multi-tenant, add a tenant_id keyword field with is_tenant=True.

  7. 7

    Index only what you filter: do not index fields that are only returned, not filtered on.

The trade-off is between index coverage and memory/write cost. Every payload index consumes memory and slows down upserts because each write must update the index. Indexing every field defensively is expensive; indexing too few fields makes filters slow. The right approach is to base the indexing decision on actual query patterns: index the fields that appear in production filters, and leave the rest unindexed. The common mistake is to store a date as a string instead of a datetime, which prevents range queries from using the datetime index and forces a slower scan. The second mistake is to store categories as a single comma-separated string instead of an array, which prevents exact-match filtering per category. The third mistake is to store permissions as a nested structure that the filter cannot address efficiently. The fourth mistake is to forget the tenant discriminator and then add it later, which requires reindexing. Version note: the datetime type, the keyword-array support, and the is_tenant flag have evolved across Qdrant releases. Verify the supported payload types and index schemas on your version before designing the schema.

javascript

Version-dependent: the supported payload schema types and the keyword-array behavior have evolved across Qdrant releases. The datetime format (ISO 8601) is stable, but the exact range API and the is_tenant flag are recent additions. Verify the schema types and the index options on your version before designing the schema, and test the filter behavior with a small fixture to confirm that the expected filtering works.

Difficulty: 7/10
Topics: Payload Schema, Payload Indexes, Filtering

Scenario Questions

0-2 years experience
  1. 1

    You store a date as a string and range queries are slow. Explain why and what you should change.

  2. 2

    A teammate stores categories as a comma-separated string. Explain why that prevents efficient category filtering.

2-5 years experience
  1. 1

    You need to filter documents by access permissions where a user may have multiple roles. Describe the schema and the filter.

  2. 2

    You have a document search system with date, category, and permissions filters. Describe the schema, the indexes, and how you would test that each filter works.

5-8 years experience
  1. 1

    Design a payload schema for a multi-tenant document search system with complex permissions, date ranges, and a document-chunk model. Specify every field, its type, and its index.

  2. 2

    You need to support a filter that combines a date range, a category, and a permission check, and the query must be fast. Describe the schema and the filter, and how you would validate performance.

8+ years experience
  1. 1

    You are designing a document search system that must support fine-grained access control with document-level and field-level permissions. Describe the schema, the filter construction, and how you prevent leaks.

  2. 2

    The permission model changes to support hierarchical groups. Describe the migration, the new schema, and how you handle the transition without downtime.

Follow-up Questions

  • How would you handle a permissions model where a user belongs to groups that are themselves nested?
  • What is the performance impact of indexing a high-cardinality keyword field, and how would you decide whether to index it?